package eu.scillman.net.tcp;

import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

import eu.scillman.interfaces.ICommConstants;
import eu.scillman.net.ConnectedMember;
import eu.scillman.net.IServer;
import eu.scillman.net.Member;

public class ServerEngine implements IServer, Runnable {
	
	/** Indicates whether the server has to shutdown. **/
	private AtomicBoolean abort = new AtomicBoolean(false);
	
	/** Indicates whether the server has been totally aborted. **/
	private AtomicBoolean aborted = new AtomicBoolean(false);
	
	/** This is the socket used by the host. **/
	private ServerSocket socket;
	
	/** The client sockets. **/
	private Socket[] clients = new Socket[ICommConstants.MAX_CONNECTIONS];
	
	/**
	 * Create a new server engine.
	 */
	public ServerEngine() {
		// Do something...
	}
	
	/**
	 * Monitoring thread.
	 */
	@Override
	public void run() {
		System.out.println("STARTING...");
		try {
			socket = new ServerSocket(ICommConstants.THEATER_PORT);
			try {
				socket.setSoTimeout(ICommConstants.CONNECTION_TIMEOUT);
				try {
					while (!abort.get()) { // While not aborting the server!
						try {
							System.out.println("Awaiting connection...");
							Socket client = socket.accept();
							{
								final String data = "data";
								PrintWriter out = new PrintWriter(client.getOutputStream(), true);
								System.out.println("Sending string: " + data);
								out.print(data);
								out.close();
							}
							client.close();
						} catch (SocketTimeoutException ex) {
							if (!abort.get()) {
								printStatusUpdate();
							}
						} catch (Exception ex) {
							throw ex; // Re-assert the exception!
						}
					}
				} catch (Exception ex) {
					abort();
					System.out.println("An error occured while running the server! Shuting down!");
				}
			} catch (Exception ex) {
				stop();
				System.out.println("Server aborted; unable to create asynchronous server.");
			}
		} catch (Exception ex) {
			System.out.println("Unable to host a server.");
		} finally {
			stop();
			aborted.set(true);
		}
	}
	
	/**
	 * Print a status update into the console!
	 */
	private void printStatusUpdate() {
		System.out.println("Server is running... (" + countClients() + "/" + clients.length + ")");
	}
	
	/**
	 * Counts the amount of connected clients.
	 * @return The amount of connected clients. [0, MAX_CONNECTIONS>
	 */
	private int countClients() {
		int i = 0, total = 0;
		
		do {
			if (clients[i] != null) {
				total++;
			}
			
			i++;
		} while (i < clients.length);
		
		return total;
	}
	
	/**
	 * Shutdown the server socket.
	 */
	private void stop() {
		if (socket != null) {
			try {
				if (!socket.isClosed()) {
					socket.close();
				}
			} catch (Exception ex) {
				System.out.println("Unable to shutdown the server socket.");
			} finally {
				socket = null;
			}
		}
	}
	
	/**
	 * {@inheritDoc}
	 */
	public boolean hold() {
		int i = 0;
		
		do {
			try {
				Thread.sleep(100);
			} catch (Exception ex) {
				System.out.println("Unable to hold thread!");
			} finally {
				i++;
			}
		} while (i < 100 && !aborted.get());
		
		if (i == 100) {
			System.out.println("Reached hold() limit");
			return false;
		}
		
		return true;
	}
	
	/**
	 * Shutdown the server.
	 */
	public void abort() {
		abort.set(true);
	}
	
	public void shutdown() {
		this.abort();
	}
	
public void send(String data) {
		
	}
	public byte[] receive() {
		return null;
	}

	@Override
	public void bind(Member localAddress) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void listen() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public List<ConnectedMember> getMembers() {
		// TODO Auto-generated method stub
		return null;
	}
}
